//
// (C) Copyright 2009 Irantha Suwandarathna (irantha@gmail.com)
// All rights reserved.
//

/* Copyright (c) 2001-2008, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


using System;
using System.Collections.Generic;
using System.IO;
using EffiProzDB.Lib;
using EffiProzDB.Persist;



/**
 * Wrapper for java.util.Properties to limit values to Specific types and
 * allow saving and loading.<p>
 *
 * @author fredt@users
 * @version 1.7.2
 * @since 1.7.0
 */

namespace EffiProzDB
{

    public class HsqlProperties
    {

        public static int NO_VALUE_FOR_KEY = 1;
        protected string fileName;
        protected Properties stringProps;
        public int[] errorCodes = new int[0];
        public String[] errorKeys = new String[0];
        protected HSQLFileAccess fa;


        public HsqlProperties()
        {
            stringProps = new Properties();
            fileName = null;
        }

        public HsqlProperties(string name)
        {

            stringProps = new Properties();
            fileName = name;
            fa = FileUtil.GetDefaultInstance();

        }

        public HsqlProperties(string name, HSQLFileAccess accessor)
        {

            stringProps = new Properties();
            fileName = name;   
            fa = accessor;
        }

        public HsqlProperties(Properties props)
        {
            stringProps = props;
        }

        public void setFileName(string name)
        {
            fileName = name;
        }

        public string setProperty(string key, int value)
        {
            return setProperty(key, (value.ToString()));
        }

        public string setProperty(string key, bool value)
        {
            return setProperty(key, (value.ToString()));
        }

        public string setProperty(string key, string value)
        {
            stringProps[key] = value;
            return (String)key;
        }

        public string setPropertyIfNotExists(string key, string value)
        {
            return stringProps.ContainsKey(key) ? key : setProperty(key, value);
        }

        public Properties getProperties()
        {
            return stringProps;
        }

        public string getProperty(string key)
        {
            return stringProps.GetProperty(key);
        }

        public string getProperty(string key, string defaultValue)
        {
            return stringProps.ContainsKey(key) ? stringProps[key] : (defaultValue);
        }

        public int getIntegerProperty(string key, int defaultValue)
        {

            string prop = getProperty(key);

            try
            {
                if (prop != null)
                {
                    defaultValue = int.Parse(prop);
                }
            }
            catch (Exception ) { }

            return defaultValue;
        }

        public int getIntegerProperty(string key, int defaultValue, int minimum,
                                      int maximum)
        {

            string prop = getProperty(key);
            
            try
            {
                defaultValue = int.Parse(prop);
            }
            catch (Exception) { }
           

            if (defaultValue < minimum)
            {
                defaultValue = minimum;
        
            }
            else if (defaultValue > maximum)
            {
                defaultValue = maximum;
           
            }

            return defaultValue;
        }

        /**
         * Choice limited to values list, defaultValue must be _in the values list.
         */
        public int getIntegerProperty(string key, int defaultValue, int[] values)
        {

            string prop = getProperty(key);
            int value = defaultValue;

            try
            {
                if (prop != null)
                {
                    value = int.Parse(prop);
                }
            }
            catch (FormatException ) { }

            if (Array.IndexOf(values, value) == -1)
            {
                return defaultValue;
            }

            return value;
        }

        public bool isPropertyTrue(string key)
        {
            return isPropertyTrue(key, false);
        }

        public bool isPropertyTrue(string key, bool defaultValue)
        {
            string value;
            try
            {
                value = stringProps[key];
            }
            catch (KeyNotFoundException)
            {
                return defaultValue;
            }         

            return value.ToLower().Equals("true");
        }

        public void removeProperty(string key)
        {
            stringProps.Remove(key);
        }

        public void addProperties(Dictionary<string, string> props) {

        if (props == null) {
            return;
        }

        var keys = props.Keys;

        foreach (var key in keys) {   

            stringProps.SetProperty(key, props[key]);
        }
    }

        public void addProperties(HsqlProperties props)
        {

            if (props == null)
            {
                return;
            }

            addProperties(props.stringProps);
        }

        // oj@openoffice.org
        public bool checkFileExists()
        {

            string propFilename = fileName + ".properties";

            return fa.IsStreamElement(propFilename);
        }

        public virtual bool load()
        {

            if (!checkFileExists())
            {
                return false;
            }

            if (fileName == null || fileName.Length == 0)
            {
                throw new FileNotFoundException(
                    Trace.getMessage(Trace.HsqlProperties_load));
            }

         
            string propsFilename = fileName + ".properties";

            // oj@openoffice.org

            stringProps.Load(propsFilename);            

            return true;
        }

        /**
         *  Saves the properties.
         */
        public virtual void save()
        {

            if (fileName == null || fileName.Length == 0)
            {
                throw new FileNotFoundException(
                    Trace.getMessage(Trace.HsqlProperties_load));
            }

            string filestring = fileName + ".properties";

            save(filestring);
        }

        /**
         *  Saves the properties using JDK2 method if present, otherwise JDK1.
         */
        public void save(string fileString)
        {

            // oj@openoffice.org
            fa.CreateParentDirs(fileString);

            Stream fos = fa.OpenOutputStreamElement(fileString);
            IFileSync outDescriptor = fa.GetFileSync(fos);

            stringProps.Store(fos , HsqlDatabaseProperties.PRODUCT_NAME + " "
                + HsqlDatabaseProperties.THIS_FULL_VERSION );
           
            fos.Flush();
            outDescriptor.Sync();
            fos.Close();

            return;
        }

        /**
         * Adds the error code and the key to the list of errors. This list
         * is populated during construction or addition of elements and is used
         * outside this class to act upon the errors.
         */
        private void addError(int code, string key)
        {
            Array.Resize<int>(ref errorCodes, errorCodes.Length + 1);
            Array.Resize<string>(ref errorKeys, errorKeys.Length + 1);
           
            errorCodes[errorCodes.Length - 1] = code;
            errorKeys[errorKeys.Length - 1] = key;
        }

        /**
         * Creates and populates an HsqlProperties Object from the arguments
         * array of a Main method. Properties are _in the form of "-key value"
         * pairs. Each key is prefixed with the type argument and a dot before
         * being inserted into the properties Object. <p>
         *
         * "-?" is treated as a key with no value and not inserted.
         */
        public static HsqlProperties argArrayToProps(string[] arg, string type)
        {

            HsqlProperties props = new HsqlProperties();

            for (int i = 0; i < arg.Length; i++)
            {
                string p = arg[i];

                if (p.StartsWith("-?"))
                {
                    props.addError(NO_VALUE_FOR_KEY, p.Substring(1));
                }
                else if (p[(0)] == '-')
                {
                    string value = i + 1 < arg.Length ? arg[i + 1]
                                                      : "";

                    props.setProperty(type + "." + p.Substring(1), value);

                    i++;
                }
            }

            return props;
        }

        /**
         * Creates and populates a new HsqlProperties Object using a string
         * such as "key1=value1;key2=value2". <p>
         *
         * The string that represents the = sign above is specified as pairsep
         * and the one that represents the semicolon is specified as delimiter,
         * allowing any string to be used for either.<p>
         *
         * Leading / trailing spaces around the keys and values are discarded.<p>
         *
         * The string is parsed by (1) subdividing into segments by delimiter
         * (2) subdividing each segment _in two by finding the first instance of
         * the pairsep (3) trimming each pair of segments from step 2 and
         * inserting into the properties object.<p>
         *
         * Each key is prefixed with the type argument and a dot before being
         * inserted.<p>
         *
         * Any key without a value is added to the list of errors.
         */
        public static HsqlProperties delimitedArgPairsToProps(string s,
                string pairsep, string dlimiter, string type)
        {

            HsqlProperties props = new HsqlProperties();
            int currentpair = 0;

            while (true)
            {
                int nextpair = s.IndexOf(dlimiter, currentpair);

                if (nextpair == -1)
                {
                    nextpair = s.Length;
                }

                // find value within the segment
                int valindex = s.Substring( 0 ,  nextpair - (0) ).IndexOf(pairsep,
                                           currentpair);

                if (valindex == -1)
                {
                    props.addError(NO_VALUE_FOR_KEY,
                                   s.Substring( currentpair ,  nextpair - (currentpair) ).Trim());
                }
                else
                {
                    string key = s.Substring( currentpair ,  valindex - (currentpair) ).Trim();
                    string value = s.Substring( valindex + pairsep.Length ,  nextpair - (valindex + pairsep.Length) ).Trim();

                    if (type != null)
                    {
                        key = type + "." + key;
                    }

                    props.setProperty(key, value);
                }

                if (nextpair == s.Length)
                {
                    break;
                }

                currentpair = nextpair + dlimiter.Length;
            }

            return props;
        }

        public IEnumerable<string> propertyNames()
        {
            return stringProps.PropertyNames();
        }

        public bool isEmpty()
        {
            return stringProps.Count == 0;
        }

        public String[] getErrorKeys()
        {
            return errorKeys;
        }
        /*
            public static void main(String[] argv) {

                HsqlProperties props1 = delimitedArgPairsToProps("-dbname.0", "=",
                    ";", "server");
                HsqlProperties props2 = delimitedArgPairsToProps(
                    "filename.cvs;a=123 ;  b=\\delta ;c= another; derrorkey;", "=",
                    ";", "textdb");
            }
        */
    }
}
